package com.hexagram2021.sweeper_maid;

import com.google.common.collect.Lists;
import com.hexagram2021.sweeper_maid.command.SMCommands;
import com.hexagram2021.sweeper_maid.config.SMCommonConfig;
import com.hexagram2021.sweeper_maid.save.SMSavedData;
import com.mojang.brigadier.CommandDispatcher;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.ChatFormatting;
import net.minecraft.SharedConstants;
import net.minecraft.commands.CommandSource;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.core.BlockPos;
import net.minecraft.network.chat.ClickEvent;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentUtils;
import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.SimpleContainer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec2;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.event.RegisterCommandsEvent;
import net.minecraftforge.event.TickEvent;
import net.minecraftforge.event.server.ServerStartedEvent;
import net.minecraftforge.eventbus.api.SubscribeEvent;
import net.minecraftforge.fml.ModList;
import net.minecraftforge.fml.ModLoadingContext;
import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.config.ModConfig;
import net.minecraftforge.registries.ForgeRegistries;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

@SuppressWarnings("unused")
@Mod(SweeperMaid.MODID)
public class SweeperMaid {
	public static final String MODID = "sweeper_maid";
	public static final String MODNAME = "Sweeper Maid";
	public static final String VERSION = ModList.get().getModFileById(MODID).versionString();

	public SweeperMaid() {
		ModLoadingContext.get().registerConfig(ModConfig.Type.COMMON, SMCommonConfig.getConfig());
		MinecraftForge.EVENT_BUS.register(this);
	}

	private int sweepTickRemain = 0;
	private boolean toSweep = false;
	private boolean firstTick = true;

	@SubscribeEvent
	public void registerCommands(RegisterCommandsEvent event) {
		final CommandDispatcher<CommandSourceStack> dispatcher = event.getDispatcher();
		dispatcher.register(SMCommands.register());
	}

	@SubscribeEvent
	public void onTick(TickEvent.ServerTickEvent event) {
		if(SMCommonConfig.ITEM_SWEEP_INTERVAL.get() == 0) {
			return;
		}
		switch (event.phase) {
			case START -> {
				this.sweepTickRemain -= 1;
				if(this.sweepTickRemain <= 0) {
					this.toSweep = true;
					this.sweepTickRemain = SMCommonConfig.ITEM_SWEEP_INTERVAL.get() * SharedConstants.TICKS_PER_SECOND;
				} else if(this.sweepTickRemain == 15 * SharedConstants.TICKS_PER_SECOND || this.sweepTickRemain == 30 * SharedConstants.TICKS_PER_SECOND || this.sweepTickRemain == 60 * SharedConstants.TICKS_PER_SECOND) {
					event.getServer().getPlayerList().getPlayers().forEach(player -> {
						try {
							player.connection.send(new ClientboundSetActionBarTextPacket(ComponentUtils.updateForEntity(
									createCommandSourceStack(player, player.level(), player.blockPosition()),
									Component.literal(SMCommonConfig.MESSAGE_BEFORE_SWEEP_15_30_60.get().replaceAll("\\$1", String.valueOf(this.sweepTickRemain / SharedConstants.TICKS_PER_SECOND))).withStyle(ChatFormatting.GRAY),
									player, 0
							)));
						} catch (CommandSyntaxException ignored) {
						}
					});
				} else if(this.sweepTickRemain % SharedConstants.TICKS_PER_SECOND == 0 && this.sweepTickRemain / SharedConstants.TICKS_PER_SECOND <= 10) {
					event.getServer().getPlayerList().getPlayers().forEach(player -> {
						try {
							player.connection.send(new ClientboundSetActionBarTextPacket(ComponentUtils.updateForEntity(
									createCommandSourceStack(player, player.level(), player.blockPosition()),
									Component.literal(SMCommonConfig.MESSAGE_BEFORE_SWEEP_1_10.get().replaceAll("\\$1", String.valueOf(this.sweepTickRemain / SharedConstants.TICKS_PER_SECOND))).withStyle(ChatFormatting.GOLD),
									player, 0
							)));
						} catch (CommandSyntaxException ignored) {
						}
					});
				}
			}
			case END -> {
				// 替换：从单个垃圾桶改为获取所有垃圾桶
				List<SimpleContainer> dustbins = SMSavedData.getDustbins();
				if (this.firstTick) {
					this.firstTick = false;
					this.toSweep = false;
					return;
				}
				if (!this.toSweep) return;
				this.toSweep = false;

				// 1. 保存所有垃圾桶的旧物品（原逻辑：避免清扫覆盖旧物品）
				List<SimpleContainer> oldBins = new ArrayList<>(dustbins.size());
				for (SimpleContainer bin : dustbins) {
					SimpleContainer oldBin = new SimpleContainer(bin.getContainerSize());
					// 复制旧物品并清空当前垃圾桶
					for (int i = 0; i < bin.getContainerSize(); i++) {
						oldBin.setItem(i, bin.getItem(i));
						bin.setItem(i, ItemStack.EMPTY);
					}
					oldBins.add(oldBin);
				}

				// 2. 清扫逻辑：循环分配物品到多个垃圾桶
				AtomicInteger droppedItems = new AtomicInteger();
				AtomicInteger extraEntities = new AtomicInteger();
				event.getServer().getAllLevels().forEach(serverLevel -> {
					Iterable<Entity> entities = serverLevel.getAllEntities();
					List<Entity> killedEntities = Lists.newArrayList();

					for (Entity entity : entities) {
						// 处理掉落物：尝试分配到多个垃圾桶
						if (entity instanceof ItemEntity itemEntity) {
							ItemStack stack = itemEntity.getItem().copy(); // 复制物品避免修改原栈
							// 循环每个垃圾桶，直到物品分配完成或所有桶满
							for (SimpleContainer bin : dustbins) {
								if (stack.isEmpty()) break;
								stack = bin.addItem(stack); // addItem返回未分配成功的剩余物品
							}
							droppedItems.addAndGet(1);
							killedEntities.add(itemEntity);
						}
						// 处理额外实体（原逻辑不变）
						else if (entity != null) {
							ResourceLocation typeKey = ForgeRegistries.ENTITY_TYPES.getKey(entity.getType());
							if (typeKey != null && SMCommonConfig.EXTRA_ENTITY_TYPES.get().contains(typeKey.toString())) {
								extraEntities.addAndGet(1);
								killedEntities.add(entity);
							}
						}
					}
					killedEntities.forEach(Entity::kill);
				});

				// 3. 恢复所有垃圾桶的旧物品（原逻辑：旧物品+新清扫物品共存）
				for (int i = 0; i < dustbins.size(); i++) {
					SimpleContainer bin = dustbins.get(i);
					SimpleContainer oldBin = oldBins.get(i);
					for (int j = 0; j < oldBin.getContainerSize(); j++) {
						ItemStack oldStack = oldBin.getItem(j);
						if (!oldStack.isEmpty()) {
							bin.addItem(oldStack); // 旧物品添加回垃圾桶（满则丢弃，与原逻辑一致）
						}
					}
				}
					event.getServer().getPlayerList().getPlayers().forEach(player -> {
						try {
							player.connection.send(new ClientboundSetActionBarTextPacket(ComponentUtils.updateForEntity(
									createCommandSourceStack(player, player.level(), player.blockPosition()),
									Component.literal(SMCommonConfig.MESSAGE_AFTER_SWEEP.get().replaceAll("\\$1", droppedItems.toString()).replaceAll("\\$2", extraEntities.toString())).withStyle(ChatFormatting.AQUA),
									player, 0
							)));
						} catch (CommandSyntaxException ignored) {
						}
					});
					event.getServer().getPlayerList().broadcastSystemMessage(
							Component.literal(SMCommonConfig.CHAT_MESSAGE_AFTER_SWEEP.get()).append(Component.literal("/sweepermaid dustbin").withStyle(style ->
									style.withColor(ChatFormatting.GREEN).withClickEvent(new ClickEvent(ClickEvent.Action.SUGGEST_COMMAND, "/sweepermaid dustbin")))), false
					);
					// 遍历所有垃圾桶，触发每个垃圾桶的更新（适配多垃圾桶列表）
					for (SimpleContainer dustin : dustbins) {
						dustin.setChanged();
					}
			}
		}
	}

	@SubscribeEvent
	public void onServerStarted(ServerStartedEvent event) {
		ServerLevel world = event.getServer().getLevel(Level.OVERWORLD);
		assert world != null;
		if (!world.isClientSide) {
			SMSavedData worldData = world.getDataStorage().computeIfAbsent(SMSavedData::new, SMSavedData::new, SMSavedData.SAVED_DATA_NAME);
			SMSavedData.setInstance(worldData);
		}
	}

	private static CommandSourceStack createCommandSourceStack(Player player, Level level, BlockPos blockPos) {
		return new CommandSourceStack(CommandSource.NULL, Vec3.atCenterOf(blockPos), Vec2.ZERO, (ServerLevel)level, 2, player.getName().getString(), player.getDisplayName(), level.getServer(), player);
	}
}
